home *** CD-ROM | disk | FTP | other *** search
- /*
- * Timers and process delays work differently under POSIX. The entire system
- * is driven on a single select() call, which uses the timeout to detect alarms
- * and the file descriptors to detect input. An itimer is used to allow
- * keyboard input to continue during lengthy activities --- which I tried to
- * avoid for portability reasons, but it behaves *real* ugly otherwise.
- * Especially when LakeSW.ampr.org lets 350K of SMTP mail pile up...
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <signal.h>
- #include "hardware.h"
- #ifdef M_UNIX
- #include <time.h>
- #include <sys/select.h>
- #else
- #include <sys/time.h>
- #endif
- #include "timer.h"
- #include "proc.h"
- #include "unixtm.h"
- #include "socket.h"
-
- #ifdef NO_GETTOD
- #include <sys/timeb.h>
- #endif
-
- #ifdef M_UNIX
- #ifndef bzero
- /* stupid bug in SCO 3.2.2 (is there any other kind for them?) */
- #define bzero(s,n) memset((s),0,(n))
- #endif
- #endif
-
- /* avoid collision with libc */
- #define psignal j_psignal
-
- /* and undo a collision avoidance, since we need the real one */
- #undef malloc
- #undef free
- extern void *malloc __ARGS((size_t));
- extern void free __ARGS((void *));
-
- /* Don't use this yet... something's still calling malloc() directly */
- #undef LMCHECK /* TEST memory allocation checker */
-
- struct io
- {
- struct io *next;
- int fd;
- void *event;
- };
-
- char Hashtab[256];
- int Tick;
- int Keyboard;
- int32 Clock;
-
- static int __istate = 1;
- static struct timeval Starttime;
- static struct io *Events;
- static int Shell;
-
- /*****************************************************************************\
- * Miscellanous functions not found in Unix *
- \*****************************************************************************/
-
- unsigned long
- filelength(fd)
- int fd;
- {
- static struct stat sb;
-
- if (fstat(fd, &sb) == -1)
- return 0;
- return sb.st_size;
- }
-
- #ifdef NEED_STRCASECMP
-
- int
- strcasecmp(s1, s2)
- register char *s1, *s2;
- {
- while (*s1 && *s2 && tolower(*s1) == tolower(*s2))
- s1++, s2++;
- return tolower(*s1) - tolower(*s2);
- }
-
- #endif
-
- #ifdef NEED_STRNCASECMP
-
- int
- strncasecmp(s1, s2, n)
- register char *s1, *s2;
- int n;
- {
- while (n && *s1 && *s2 && tolower(*s1) == tolower(*s2))
- s1++, s2++, n--;
- return n? tolower(*s1) - tolower(*s2): 0;
- }
-
- #endif
-
- char *
- strupr(s)
- char *s;
- {
- register char *p = s;
-
- while (*p)
- *p = toupper(*p), p++;
- return s;
- }
-
- char *
- strlwr(s)
- char *s;
- {
- register char *p = s;
-
- while (*p)
- *p = tolower(*p), p++;
- return s;
- }
-
- char *
- stpcpy(d, s)
- register char *d;
- register const char *s;
- {
- while (*s)
- *d++ = *s++;
- *d = '\0';
- return d;
- }
-
- char *
- itoa(n, buf, base)
- int n, base;
- char *buf;
- {
- if (base != 10)
- tprintf("WARNING: itoa() passed radix %d\n", base);
- sprintf(buf, "%d", n);
- return buf;
- }
-
- /* This was in assembler, I assume for speed. */
-
- int16
- hash_ip(ipaddr)
- long ipaddr;
- {
- int h;
-
- h = ((ipaddr >> 16) & 0xFFFF) ^ (ipaddr & 0xFFFF);
- return Hashtab[((h >> 8) & 0xFF) ^ (h & 0xFF)];
- }
-
- /*****************************************************************************\
- * Memory interface *
- \*****************************************************************************/
-
- #ifdef LMCHECK
-
- /*
- * We track memory allocation via hash buckets. This is a fixed-size hash
- * table with variable-sized buckets: we hash an address by taking some bits
- * from it, and store the result in a slot in the bucket.
- */
-
- #define NMWHASH 4096 /* number of hash buckets - s/b power of 2 */
- #define LOGNMWH 12 /* log2(NMWHASH) */
- #define NMWHSHIFT 8 /* ptr shift for hashing */
- #define NMWHSLOT 32 /* initial slots in bucket */
-
- struct hbucket
- {
- void **ptr;
- int nptr;
- };
-
- static struct hbucket MWhashtab[NMWHASH];
-
- static void
- mwhash(void *p)
- {
- register struct hbucket *h;
- int i;
-
- h = MWhashtab + (((unsigned long) p >> NMWHSHIFT) & (NMWHASH - 1));
- if (!h->nptr)
- {
- h->ptr = malloc(NMWHSLOT * sizeof *h->ptr);
- memset(h->ptr, 0, NMWHSLOT * sizeof *h->ptr);
- i = 0;
- }
- else
- {
- for (i = 0; i < h->nptr; i++)
- {
- if (!h->ptr[i])
- break;
- }
- if (i == h->nptr)
- {
- h->ptr = realloc(h->ptr, (h->nptr + NMWHSLOT) * sizeof *h->ptr);
- memset(h->ptr + h->nptr, 0, NMWHSLOT * sizeof *h->ptr);
- h->nptr += NMWHSLOT;
- }
- }
- h->ptr[i] = p;
- }
-
- static int
- mwunhash(void *p)
- {
- register struct hbucket *h;
- int i;
-
- h = MWhashtab + (((unsigned long) p >> NMWHSHIFT) & (NMWHASH - 1));
- for (i = h->nptr; i--; )
- {
- if (h->ptr[i] == p)
- break;
- }
- if (i == -1)
- return 0;
- h->ptr[i] = 0;
- return 1;
- }
-
- #endif
-
- void *
- mallocw(unsigned size)
- {
- void *p;
-
- if (!(p = malloc(size)))
- where_outta_here(1);
- #ifdef LMCHECK
- mwhash(p);
- #endif
- return p;
- }
-
- void *
- callocw(cnt, size)
- unsigned cnt, size;
- {
- void *p;
-
- if (!(p = malloc(size * cnt)))
- where_outta_here(1);
- #ifdef LMCHECK
- mwhash(p);
- #endif
- memset(p, 0, size * cnt);
- return p;
- }
-
- void
- j_free(void *p)
- {
- #ifdef LMCHECK
- if (!mwunhash(p))
- {
- printf("\r\7WARNING: free()ing unknown pointer %lx\r\n",
- (unsigned long) p);
- return;
- }
- #endif
- free(p);
- }
-
- #if 0
-
- /*
- * these should by rights try to determine the available VM... oh, well
- */
-
- unsigned long
- availmem()
- {
- #ifdef linux
- return 0xC0000000 - (unsigned long) sbrk(0);
- #else
- return 0x80000000 - (unsigned long) sbrk(0);
- #endif
- }
-
- unsigned long
- farcoreleft()
- {
- #ifdef linux
- return 0xC0000000 - (unsigned long) sbrk(0);
- #else
- return 0x80000000 - (unsigned long) sbrk(0);
- #endif
- }
-
- unsigned long
- getss()
- {
- return 0;
- }
-
- #endif
-
- /*****************************************************************************\
- * Interrupt management - null *
- \*****************************************************************************/
-
- int
- istate()
- {
- return __istate;
- }
-
- int
- dirps()
- {
- sigset_t s;
- int ops;
-
- if (__istate)
- {
- sigemptyset(&s);
- sigaddset(&s, SIGALRM);
- sigprocmask(SIG_BLOCK, &s, (sigset_t *) 0);
- }
- ops = __istate;
- __istate = 0;
- return ops;
- }
-
- void
- restore(ps)
- int ps;
- {
- sigset_t s;
-
- if (__istate != ps)
- {
- sigemptyset(&s);
- sigaddset(&s, SIGALRM);
- sigprocmask((ps? SIG_UNBLOCK: SIG_BLOCK), &s, (sigset_t *) 0);
- }
- __istate = ps;
- }
-
- /*****************************************************************************\
- * Date and time functions *
- \*****************************************************************************/
-
- long
- secclock()
- {
- #ifdef NO_GETTOD
- static struct timeb t;
-
- ftime(&t);
- return t.time - Starttime.tv_sec - (Starttime.tv_usec > t.millitm * 1000);
- #else
- static struct timezone tz;
- static struct timeval tv;
-
- gettimeofday(&tv, &tz);
- return tv.tv_sec - Starttime.tv_sec - (Starttime.tv_usec > tv.tv_usec);
- #endif
- }
-
- long
- msclock()
- {
- #ifdef NO_GETTOD
- static struct timeb t;
-
- ftime(&t);
- t.millitm *= 1000;
- if (t.millitm < Starttime.tv_usec)
- {
- t.millitm += 1000000;
- t.time--;
- }
- return (t.time - Starttime.tv_sec) * 1000 +
- (t.millitm - Starttime.tv_usec) / 1000;
- #else
- static struct timezone tz;
- static struct timeval tv;
-
- gettimeofday(&tv, &tz);
- if (tv.tv_usec < Starttime.tv_usec)
- {
- tv.tv_usec += 1000000;
- tv.tv_sec--;
- }
- return (tv.tv_sec - Starttime.tv_sec) * 1000 +
- (tv.tv_usec - Starttime.tv_usec) / 1000;
- #endif
- }
-
- static void
- init_time(void)
- {
- #ifdef NO_GETTOD
- struct timeb t;
-
- ftime(&t);
- Starttime.tv_sec = t.time;
- Starttime.tv_usec = t.millitm * 1000;
- #else
- struct timezone tz;
-
- gettimeofday(&Starttime, &tz);
- #endif
- }
-
- void
- gettime(tp)
- struct time *tp;
- {
- struct tm *tm;
- #ifdef NO_GETTOD
- static struct timeb tb;
-
- ftime(&tb);
- tm = localtime(&tb.time);
- tp->ti_hund = tb.millitm / 10;
- #else
- static struct timeval tv;
- static struct timezone tz;
-
- gettimeofday(&tv, &tz);
- tm = localtime(&tv.tv_sec);
- tp->ti_hund = tv.tv_usec / 10000;
- #endif
- tp->ti_hour = tm->tm_hour;
- tp->ti_min = tm->tm_min;
- tp->ti_sec = tm->tm_sec;
- }
-
- void
- getdate(dp)
- struct date *dp;
- {
- struct tm *tm;
- #ifdef NO_GETTOD
- static struct timeb tb;
-
- ftime(&tb);
- tm = localtime(&tb.time);
- #else
- static struct timeval tv;
- static struct timezone tz;
-
- gettimeofday(&tv, &tz);
- tm = localtime(&tv.tv_sec);
- #endif
- dp->da_year = tm->tm_year + 1900;
- dp->da_mon = tm->tm_mon + 1;
- dp->da_day = tm->tm_mday;
- }
-
- long
- dostounix(dp, tp)
- struct date *dp;
- struct time *tp;
- {
- static struct tm tm;
- struct tm *tx;
- long now;
-
- tm.tm_year = dp->da_year - 1900;
- tm.tm_mon = dp->da_mon - 1;
- tm.tm_mday = dp->da_day;
- tm.tm_hour = tp->ti_hour;
- tm.tm_min = tp->ti_min;
- tm.tm_sec = tp->ti_sec;
- /* This desperately needs to be fixed. How? */
- time(&now);
- tx = localtime(&now);
- tm.tm_isdst = tx->tm_isdst;
- return mktime(&tm);
- }
-
- /*****************************************************************************\
- * Timers, I/O and scheduling *
- \*****************************************************************************/
-
- void
- register_io(fd, event)
- int fd;
- void *event;
- {
- struct io *evp;
-
- if (!(evp = mallocw(sizeof *evp)))
- {
- tprintf("register_io: no memory for event\n");
- where_outta_here(1);
- }
- evp->fd = fd;
- evp->event = event;
- evp->next = Events;
- Events = evp;
- }
-
- void
- unregister_io(fd)
- int fd;
- {
- struct io *evp, *evc;
-
- for (evp = 0, evc = Events; evc->fd != fd; evp = evc, evc = evc->next)
- ;
- if (!evc)
- {
- tprintf("unregister_io: unknown fd\n");
- return;
- }
- if (evp)
- evp->next = evc->next;
- else
- Events = evc->next;
- j_free(evc);
- }
-
- static void
- ouch(int sig)
- {
- struct sigaction sa;
-
- sa.sa_handler = SIG_DFL;
- sa.sa_flags = 0;
- sigaction(SIGSEGV, &sa, (struct sigaction *) 0);
- #ifdef SIGBUS
- sigaction(SIGBUS, &sa, (struct sigaction *) 0);
- #endif
- if (fork() == 0)
- {
- sigaction(sig, &sa, (struct sigaction *) 0);
- raise(sig);
- }
- detach_all_asy();
- exit(1);
- }
-
- static void
- ding(int i)
- {
- extern struct timer *Timers;
- static struct timeval tv;
- struct timeval *tvp;
- static fd_set fds;
- struct io *evp;
- long oclock;
-
- /* do pending output */
- if (!i)
- {
- tflush();
- rflush();
- }
- /* collect input events to wait on */
- FD_ZERO(&fds);
- for (evp = Events; evp; evp = evp->next)
- FD_SET(evp->fd, &fds);
- /* get time until next timer; if zero, fake a very large one */
- /* if we have a nonzero argument, we're a timer tick; poll, don't block */
- if (i)
- {
- tv.tv_sec = tv.tv_usec = 0;
- tvp = &tv;
- }
- else if (!Timers)
- tvp = 0;
- else
- {
- tv.tv_sec = (Timers->expiration - Clock) * MSPTICK;
- if (tv.tv_sec <= 0)
- tv.tv_sec = 0;
- tv.tv_usec = (tv.tv_sec % 1000) * 1000;
- tv.tv_sec /= 1000;
- tvp = &tv;
- }
- /* check for I/O */
- select(FD_SETSIZE, &fds, 0, 0, tvp);
- /* signal events for pending I/O */
- for (evp = Events; evp; evp = evp->next)
- {
- if (FD_ISSET(evp->fd, &fds))
- psignal(evp->event, 1);
- }
- /* run any due timers */
- psignal(&Tick, 1);
- /* and update the system time */
- oclock = Clock;
- Clock = msclock() / MSPTICK;
- Tick = Clock - oclock;
- }
-
-
- static void
- init_tick(void)
- {
- struct sigaction sa;
- struct itimerval it;
-
- sa.sa_flags = 0;
- sa.sa_handler = ding;
- sigaction(SIGALRM, &sa, (struct sigaction *) 0);
- it.it_interval.tv_sec = 0;
- it.it_interval.tv_usec = MSPTICK * 1000;
- it.it_value = it.it_interval;
- setitimer(ITIMER_REAL, &it, (struct itimerval *) 0);
- }
-
- static void
- deinit_tick(void)
- {
- struct itimerval it;
-
- it.it_interval.tv_sec = it.it_interval.tv_usec = 0;
- it.it_value = it.it_interval;
- setitimer(ITIMER_REAL, &it, (struct itimerval *) 0);
- }
-
- void
- init_sys(int no_itimer)
- {
- struct sigaction sa;
-
- init_time();
- register_io(0, &Keyboard);
- sa.sa_handler = ouch;
- sa.sa_flags = 0;
- sigaction(SIGSEGV, &sa, (struct sigaction *) 0);
- #ifdef SIGBUS
- sigaction(SIGBUS, &sa, (struct sigaction *) 0);
- #endif
- if (!no_itimer)
- init_tick();
- }
-
- void
- deinit_sys()
- {
- deinit_tick();
- unregister_io(0);
- }
-
- void
- giveup()
- {
- /* suspend heartbeat */
- deinit_tick();
- /* block for I/O */
- ding(0);
- /* and reactivate the tick */
- init_tick();
- }
-
- #ifdef SHELL
-
- int
- doshell(int argc, char **argv, void *p)
- {
- struct sigaction sa, old_int, old_quit;
- int ac, pid;
- int pi[2];
- char *av[4];
-
- /*
- * Under *ix, one would expect ! or shell to work like in other *ix
- * programs. Since we don't really want to emulate DOS doshell()'s
- * special handling for argv[1] == "/c" anyway :-) we will handle
- * this properly.
- *
- * argc < 2: ${SHELL:-/bin/sh}
- * >= 2: concatenate and /bin/sh -c it (NOT $SHELL)!
- */
- if (!sm_usestdio())
- {
- tprintf("Not running on NOS console\n");
- return 1;
- }
- if (pipe(pi) == -1)
- {
- tprintf("Can't create pipe for subprocess\n");
- return 1;
- }
- switch (pid = fork())
- {
- case -1:
- tprintf("Fork failed\n");
- return 1;
- case 0:
- close(pi[0]);
- ac = 1;
- if (argc > 1 || !(av[0] = getenv("SHELL")))
- av[0] = "/bin/sh";
- if (argc > 1)
- {
- av[ac++] = "-c";
- av[ac++] = argv[1];
- }
- av[ac] = 0;
- execv(av[0], av);
- _exit(1);
- default:
- close(pi[1]);
- iosuspend();
- unregister_io(0);
- register_io(pi[0], &Shell);
- /* signal handling... */
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- sa.sa_handler = SIG_IGN;
- sigaction(SIGINT, &sa, &old_int);
- sigaction(SIGQUIT, &sa, &old_quit);
- pwait(&Shell);
- sigaction(SIGQUIT, &old_quit, 0);
- sigaction(SIGINT, &old_int, 0);
- unregister_io(pi[0]);
- close(pi[0]);
- register_io(0, &Keyboard);
- ioresume();
- }
- return 0;
- }
-
- #endif
-